/*
 * Copyright (c) 2014. Sensoro Inc.
 * All rights reserved.
 */

package com.sensoro.beacon.kit;

import android.os.Parcel;
import android.os.Parcelable;

import java.io.Serializable;

/**
 * The beacon setting class,this class can set or get transmit power,
 * advertising interval of the beacon.It also can control energy saving mode,
 * password status.
 */
public class BaseSettings implements Parcelable {
    static final int MESURED_POWER_UNKNOW = Integer.MAX_VALUE;
    static final int UUID_STRING_LENGTH = 36;
    static final int MAX_65535 = 65535;
    static final int MIN_0 = 0;
    static final int MAX_127 = 127;
    static final int MIN___128 = -128;

    TransmitPower transmitPower;
    AdvertisingInterval advertisingInterval;
    EnergySavingMode energySavingMode;
    int measuredPower;

    public BaseSettings() {
        transmitPower = TransmitPower.UNKNOWN;
        advertisingInterval = AdvertisingInterval.UNKNOWN;
        energySavingMode = EnergySavingMode.UNKNOWN;
        measuredPower = MESURED_POWER_UNKNOW;
    }

    @Override
    public String toString() {
        return "BaseSettings{" + "transmitPower=" + transmitPower + ", advertisingInterval=" + advertisingInterval + ", energySavingMode=" + energySavingMode + ", measuredPower=" + measuredPower + '}';
    }

    /**
     * Set the transmit power of the beacon.
     *
     * @param transmitPower The value of the transmit power <br/>
     *                      {@link com.sensoro.beacon.kit.BaseSettings.TransmitPower}
     */
    public void setTransmitPower(TransmitPower transmitPower) {
        this.transmitPower = transmitPower;
    }

    /**
     * Get the transmit power of the beacon.
     *
     * @return value of transmit power <br/>
     * {@link com.sensoro.beacon.kit.BaseSettings.TransmitPower}
     */
    public TransmitPower getTransmitPower() {
        return transmitPower;
    }

    /**
     * Set the advertising interval of the beacon.
     *
     * @param advertisingInterval The value of the advertising interval <br/>
     *                            {@link com.sensoro.beacon.kit.BaseSettings.AdvertisingInterval}
     */
    public void setAdvertisingInterval(AdvertisingInterval advertisingInterval) {
        this.advertisingInterval = advertisingInterval;
    }

    /**
     * Get the advertising interval of the beacon
     *
     * @return value of advertising interval <br/>
     * {@link com.sensoro.beacon.kit.BaseSettings.AdvertisingInterval}
     */
    public AdvertisingInterval getAdvertisingInterval() {
        return advertisingInterval;
    }

    /**
     * Set the energy saving mode of the beacon.The energy saving mode can be
     * controled by the light sensor if you set.
     *
     * @param energySavingMode The mode of beacon <br/>
     *                         {@link com.sensoro.beacon.kit.BaseSettings.EnergySavingMode}
     */
    public void setEnergySavingMode(EnergySavingMode energySavingMode) {
        this.energySavingMode = energySavingMode;
    }

    /**
     * Get energy saving mode of the beacon.
     *
     * @return saving mode of beacon <br/>
     * {@link com.sensoro.beacon.kit.BaseSettings.EnergySavingMode}
     */
    public EnergySavingMode getEnergySavingMode() {
        return energySavingMode;
    }

    /**
     * <p>
     * Set the measured power of the beacon.
     * </p>
     * range:-128~127
     *
     * @param measuredPower The new value of measured power(mrssi).
     */
    public void setMeasuredPower(int measuredPower) {
        this.measuredPower = measuredPower;
    }

    /**
     * Get the measured rssi(mrssi) of the beacon.
     *
     * @return value of measured rssi(mrssi).
     */
    public int getMeasuredPower() {
        return measuredPower;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(transmitPower.ordinal());
        out.writeInt(advertisingInterval.ordinal());
        out.writeInt(energySavingMode.ordinal());
        out.writeInt(measuredPower);
    }

    public static final Creator<BaseSettings> CREATOR = new Creator<BaseSettings>() {

        @Override
        public BaseSettings createFromParcel(Parcel parcel) {
            return new BaseSettings(parcel);
        }

        @Override
        public BaseSettings[] newArray(int size) {
            return new BaseSettings[size];
        }
    };

    private BaseSettings(Parcel in) {
        transmitPower = TransmitPower.values()[in.readInt()];
        advertisingInterval = AdvertisingInterval.values()[in.readInt()];
        energySavingMode = EnergySavingMode.values()[in.readInt()];
        measuredPower = in.readInt();
    }

    /**
     * The advertising interval enum of the beacon.
     */
    public enum AdvertisingInterval implements Serializable {
        /**
         * Unknown.
         */
        UNKNOWN,
        /**
         * The advertising interval is 100 ms.
         */
        ADVERTISING_INTERVAL_100,    //0x00 100ms
        /**
         * The advertising interval is 152.5 ms.
         */
        ADVERTISING_INTERVAL_152_5,  //0x01 152.5ms
        /**
         * The advertising interval is 211.25 ms.
         */
        ADVERTISING_INTERVAL_211_25,    //0x02 211.25ms
        /**
         * The advertising interval is 318.75 ms.
         */
        ADVERTISING_INTERVAL_318_75,    //0x03 318.75ms
        /**
         * The advertising interval is 417.5 ms.
         */
        ADVERTISING_INTERVAL_417_5, //0x04 417.5ms
        /**
         * The advertising interval is 546.25 ms.
         */
        ADVERTISING_INTERVAL_546_25, //0x05 546.25ms
        /**
         * The advertising interval is 760 ms.
         */
        ADVERTISING_INTERVAL_760,    //0x06 760ms
        /**
         * The advertising interval is 852.5 ms.
         */
        ADVERTISING_INTERVAL_852_5,   //0x07 852.5ms
        /**
         * The advertising interval is 1022.5 ms.
         */
        ADVERTISING_INTERVAL_1022_5,    //0x08 1022.5ms
        /**
         * The advertising interval is 1285 ms.
         */
        ADVERTISING_INTERVAL_1285;  //0x09 1285ms

        /**
         * Get the millisecond of AdvertisingInterval.</br>
         *
         * @param advertisingInterval
         * @return
         */
        public static Double getAdvertisingIntervalValue(AdvertisingInterval advertisingInterval) {
            switch (advertisingInterval) {
                case ADVERTISING_INTERVAL_100:
                    return 100.0;
                case ADVERTISING_INTERVAL_152_5:
                    return 152.5;
                case ADVERTISING_INTERVAL_211_25:
                    return 211.25;
                case ADVERTISING_INTERVAL_318_75:
                    return 318.75;
                case ADVERTISING_INTERVAL_417_5:
                    return 417.5;
                case ADVERTISING_INTERVAL_546_25:
                    return 546.25;
                case ADVERTISING_INTERVAL_760:
                    return 760.0;
                case ADVERTISING_INTERVAL_852_5:
                    return 852.5;
                case ADVERTISING_INTERVAL_1022_5:
                    return 1022.5;
                case ADVERTISING_INTERVAL_1285:
                    return 1285.0;
                default:
                    return null;
            }
        }
    }

    /**
     * The energy saving mode enum of the beacon.
     */
    public enum EnergySavingMode implements Serializable {
        /**
         * Unknown.
         */
        UNKNOWN,
        /**
         * Disable saving mode.
         */
        NONE,   //0
        /**
         * Enable light sensor saving mode.
         */
        LIGHT_SENSOR    //1
    }

    /**
     * The transmit power enum of the beacon. </br>
     * The coverage of the LEVEL0 is minimum, and the coverage of LEVEL11 is maximum.</br>
     * Not all values apply to all kinds of beacon. For more details to see {@link <a href="https://github.com/Sensoro/SDK-Android">https://github.com/Sensoro/SDK-Android</a>}.
     */
    public enum TransmitPower implements Serializable {
        /**
         * Unknown.
         */
        UNKNOWN,
        LEVEL0, // 0x00
        LEVEL1, // 0x01
        LEVEL2, // 0x02
        LEVEL3, // 0x03
        LEVEL4, // 0x04
        LEVEL5, // 0x05
        LEVEL6, // 0x06
        LEVEL7, // 0x07
        LEVEL8, // 0x08
        LEVEL9, // 0x09
        LEVEL10, // 0x0A
        LEVEL11; // 0x0B

        /**
         * Check whether the value of transmit power is micro by model.</br>
         * If the transmit power is {@link com.sensoro.beacon.kit.BaseSettings.TransmitPower#UNKNOWN} or the value of model is invalid, it will return null.
         *
         * @param transmitPower
         * @param model
         * @return
         */
        public static Boolean isMicroTX(TransmitPower transmitPower, String model) {
            if (model.equals(Beacon.HV_A0)) {
                return false;
            } else  if (model.equals(Beacon.HV_B0)) {
                return false;
            } else  if (model.equals(Beacon.HV_C0)) {
                if (transmitPower == UNKNOWN){
                    return null;
                } else if (transmitPower.compareTo(LEVEL4) < 0){
                    return true;
                } else {
                    return false;
                }
            }
            return null;
        }

        /**
         * Get the real value of transmit power by model.</br>
         * If the transmit power is {@link com.sensoro.beacon.kit.BaseSettings.TransmitPower#UNKNOWN} or the value of model is invalid, it will return null.
         *
         * @param transmitPower
         * @param model
         * @return
         */
        public static Integer getTransmitPowerValue(TransmitPower transmitPower, String model) {
            if (model.equals(Beacon.HV_A0)) {
                switch (transmitPower) {
                    case LEVEL0:
                        return -23;
                    case LEVEL1:
                        return -6;
                    case LEVEL2:
                        return 0;
                    default:
                        return null;
                }
            } else if (model.equals(Beacon.HV_B0)) {
                switch (transmitPower) {
                    case LEVEL0:
                        return -30;
                    case LEVEL1:
                        return -20;
                    case LEVEL2:
                        return -16;
                    case LEVEL3:
                        return -12;
                    case LEVEL4:
                        return -8;
                    case LEVEL5:
                        return -4;
                    case LEVEL6:
                        return 0;
                    case LEVEL7:
                        return +4;
                    default:
                        return null;
                }
            } else if (model.equals(Beacon.HV_C0)) {
                switch (transmitPower) {
                    case LEVEL0:
                        return -30;
                    case LEVEL1:
                        return -20;
                    case LEVEL2:
                        return -16;
                    case LEVEL3:
                        return -12;
                    case LEVEL4:
                        return -30;
                    case LEVEL5:
                        return -20;
                    case LEVEL6:
                        return -16;
                    case LEVEL7:
                        return -12;
                    case LEVEL8:
                        return -8;
                    case LEVEL9:
                        return -4;
                    case LEVEL10:
                        return 0;
                    case LEVEL11:
                        return +4;
                    default:
                        return null;
                }
            } else {
                return null;
            }
        }
    }

    /**
     * The secure broadcast interval.
     */
    public enum SecureBroadcastInterval implements Serializable {
        /**
         * Unknown.
         */
        UNKNOWN,
        /**
         * Disable secure broadcast.
         */
        NONE, // 0
        /**
         * The secure broadcast interval is 5 seconds.
         */
        SECURE_BROADCAST_INTERVAL_5_SECONDS, // 5
        /**
         * The secure broadcast interval is 1 minute.
         */
        SECURE_BROADCAST_INTERVAL_1_MINTE, // 60
        /**
         * The secure broadcast interval is 1 hour.
         */
        SECURE_BROADCAST_INTERVAL_1_HONR, // 60*60
        /**
         * The secure broadcast interval is 1 day.
         */
        SECURE_BROADCAST_INTERVAL_1_DAY, // 60*60*24
        /**
         * The secure broadcast interval is 7 days.
         */
        SECURE_BROADCAST_INTERVAL_7_DAYS, // 60*60*24*7
        /**
         * The secure broadcast interval is 7 days.
         */
        SECURE_BROADCAST_INTERVAL_30_DAYS // 60*60*24*30
    }
}